package com.pxmeta.circle.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.pxmeta.circle.entity.Circle;
import com.pxmeta.circle.entity.CircleUserKick;
import com.pxmeta.circle.entity.UserCircle;
import com.pxmeta.circle.entity.dto.KickUserDTO;
import com.pxmeta.circle.entity.vo.CircleUserInfoVO;
import com.pxmeta.circle.mapper.CircleUserKickMapper;
import com.pxmeta.circle.mapper.UserCircleMapper;
import com.pxmeta.circle.service.ICircleService;
import com.pxmeta.circle.service.IUserCircleService;
import com.pxmeta.common.constant.HttpStatus;
import com.pxmeta.common.core.redis.RedisCache;
import com.pxmeta.common.enums.CircleUserLevelEnum;
import com.pxmeta.common.exception.ServiceException;
import com.pxmeta.user.entity.User;
import com.pxmeta.user.entity.vo.CircleUserVO;
import com.pxmeta.user.service.IUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户圈子表 服务实现类
 * </p>
 *
 * @author wcl
 * @since 2022-05-14
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class UserCircleServiceImpl extends ServiceImpl<UserCircleMapper, UserCircle> implements IUserCircleService {

    public static final Integer CIRCLE_OWNER_USER_LEVEL = 2;
    private static final String KICK_CIRCLE_USER_KEY = "kick_circle_user_%s_%s";
    private final IUserService userService;
    private final ICircleService circleService;
    private final CircleUserKickMapper circleUserKickMapper;
    private final RedisCache redisCache;

    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public void joinCircle(UserCircle userCircle, boolean isInit) {
        Long circleId = userCircle.getCircleId();
        Circle circle = circleService.getById(circleId);
        if (null == circle) {
            throw new ServiceException("圈子不存在", HttpStatus.PARAMS_ERROR);
        }
        if (circle.getType()==0){
            userCircle.setSort(99999);
        }

        if (!isInit && circle.getType() == 1 && circle.getIsSystem() == 1){
            //如果是学校
            User user = userService.getById(userCircle.getUserId());
            String name = circle.getName();
            String schoolName = user.getSchoolName();
            if (!name.equals(schoolName)){
                throw new ServiceException("该圈子不属于你的学校！");
            }
        }
        Long userCount = circle.getUserCount();
        userCount ++;
        //圈子热度 + 1
        Long hot = circle.getHot();
        hot++;
        Circle kc = new Circle();
        kc.setId(circleId);
        kc.setHot(hot);
        kc.setUserCount(userCount);
        circleService.updateById(kc);


        boolean forbidden = checkForbiddenJoinCircle(circleId, userCircle.getUserId());
        if (forbidden) {
            throw new ServiceException("您已被禁止加入！", HttpStatus.JOIN_CIRCLE_ERROR);
        }

        String kickKey = String.format(KICK_CIRCLE_USER_KEY, circleId, userCircle.getUserId());
        Object cache = redisCache.getCacheObject(kickKey);
        if (cache != null) {
            Boolean isKick = (Boolean) cache;
            if (isKick) {
                throw new ServiceException("24小时内不能再次加入", HttpStatus.JOIN_CIRCLE_ERROR);
            }
        }

        UserCircle uc = getByUserIdAndCircleId(userCircle.getUserId(), circleId);

        if (uc != null) {
            throw new ServiceException("不可重复加入！");
        }
        this.save(userCircle);
    }

    @Override
    public List<CircleUserVO> getUserList(Long circleId, Integer page, Integer size, String name) {

        LambdaQueryWrapper<UserCircle> wrapper = Wrappers.lambdaQuery();

        if (StringUtils.isNotBlank(name)) {
            wrapper.like(UserCircle::getNickname, name);
        }
        wrapper.eq(UserCircle::getCircleId, circleId)
                .orderByDesc(UserCircle::getCreateTime);
        List<UserCircle> records = baseMapper.selectPage(new Page<>(page, size), wrapper).getRecords();
        List<Long> userIds = records.stream().map(UserCircle::getUserId).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(userIds)) {
            return Lists.newArrayList();
        }
        List<User> users = userService.listByIds(userIds);

        LinkedList<CircleUserVO> finalList = com.google.common.collect.Lists.newLinkedList();
        for (User user : users) {
            CircleUserVO circleUserVO = new CircleUserVO();
            circleUserVO.setUserId(user.getId());
            circleUserVO.setAvatar(user.getAvatar());
            for (UserCircle record : records) {
                if (user.getId().equals(record.getUserId())) {
                    if (StringUtils.isBlank(record.getNickname())){
                        circleUserVO.setNickname(user.getNickname());
                    }else {
                        circleUserVO.setNickname(record.getNickname());
                    }
                    circleUserVO.setLevel(record.getLevel());
                    break;
                }
            }
            finalList.add(circleUserVO);
        }
        finalList.sort((s1, s2) -> (s2.getLevel() - s1.getLevel()));
        return finalList;
    }


    /**
     * 踢出圈子用户
     *
     * @param userId 操作人id
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public void kickUser(Long userId, KickUserDTO dto) {
        CircleUserKick cuk = new CircleUserKick();
        BeanUtils.copyProperties(dto, cuk);
        cuk.setUserId(userId);
        circleUserKickMapper.insert(cuk);
        this.quit(dto.getKickUserId(),dto.getCircleId());
        String kickKey = String.format(KICK_CIRCLE_USER_KEY, dto.getCircleId(), dto.getKickUserId());
        redisCache.setCacheObject(kickKey, Boolean.TRUE, 1, TimeUnit.DAYS);
    }

    @Override
    public CircleUserInfoVO getUserInfo(Long userId, Long circleId) {
        LambdaQueryWrapper<UserCircle> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserCircle::getUserId, userId)
                .eq(UserCircle::getCircleId, circleId);
        UserCircle uc = this.getOne(wrapper);
        CircleUserInfoVO vo = new CircleUserInfoVO();
        vo.setLevel(uc.getLevel());
        vo.setExp(uc.getExp());
        vo.setTitle(uc.getTitle());
        vo.setNickname(uc.getNickname());
        vo.setAddTime(uc.getCreateTime());
        return vo;
    }

    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public void transferMaster(Long userId, Long circleId, Long targetUserId) {
        UserCircle uc = getByUserIdAndCircleId(userId, circleId);
        if (uc == null) {
            throw new ServiceException("当前用户不在该圈子中！", HttpStatus.PARAMS_ERROR);
        }

        if (!CircleUserLevelEnum.CREATOR.getLevel().equals(uc.getLevel())) {
            throw new ServiceException("当前用户不是圈主！", HttpStatus.PARAMS_ERROR);
        }

        UserCircle targetUc = getByUserIdAndCircleId(targetUserId, circleId);

        if (null == targetUc) {
            throw new ServiceException("要转移的用户不在该圈子中！");
        }

        targetUc.setLevel(CircleUserLevelEnum.CREATOR.getLevel());
        uc.setLevel(CircleUserLevelEnum.NORMAL.getLevel());
        this.updateById(targetUc);
        this.updateById(uc);

        //todo 审计日志
    }

    @Override
    public UserCircle getByUserIdAndCircleId(Long userId, Long circleId) {
        LambdaQueryWrapper<UserCircle> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserCircle::getUserId, userId)
                .eq(UserCircle::getCircleId, circleId);
        return this.getOne(wrapper);
    }

    @Override
    public void addAdmin(Long ownerId, Long circleId, List<Long> adminUserIds) {
        List<User> adminUsers = getAdminUserByCircleId(circleId);
        if (CollectionUtil.isNotEmpty(adminUsers) &&
                adminUsers.stream().filter(u -> !CIRCLE_OWNER_USER_LEVEL.equals(u.getCircleLevel())).count() >= 2) {

            throw new ServiceException("管理员数量上限，无法再次添加！");
        }
        UserCircle ownerUser = getByUserIdAndCircleId(ownerId, circleId);
        if (!CircleUserLevelEnum.CREATOR.getLevel().equals(ownerUser.getLevel())) {
            throw new ServiceException("你不是圈主！");
        }
        for (Long adminUserId : adminUserIds) {
            UserCircle userCircle = getByUserIdAndCircleId(adminUserId, circleId);
            if (null == userCircle) {
                throw new ServiceException("用户不在该圈子中！");
            }
            if (userCircle.getLevel() != 0) {
                throw new ServiceException("该用户不是普通成员！");
            }
            userCircle.setLevel(CircleUserLevelEnum.ADMIN.getLevel());
            this.updateById(userCircle);
        }

    }

    @Override
    public void cancelAdmin(Long circleId, Long ownerId, Long adminUserId) {
        UserCircle ownerUser = getByUserIdAndCircleId(ownerId, circleId);
        if (!CircleUserLevelEnum.CREATOR.getLevel().equals(ownerUser.getLevel())) {
            throw new ServiceException("没有权限！");
        }
        UserCircle uc = getByUserIdAndCircleId(adminUserId, circleId);
        if (null == uc) {
            throw new ServiceException("该用户不在该圈子中！");
        }
        if (!CircleUserLevelEnum.ADMIN.getLevel().equals(uc.getLevel())) {
            throw new ServiceException("该用户不是管理员！");
        }
        uc.setLevel(CircleUserLevelEnum.NORMAL.getLevel());
        this.updateById(uc);
    }

    /**
     * 解除圈子
     *
     * @param circleId
     * @param ownerId
     */
    @Override
    public void breakCircle(Long circleId, Long ownerId) {
        UserCircle uc = getByUserIdAndCircleId(ownerId, circleId);
        if (null == uc) {
            throw new ServiceException("数据不存在！");
        }
        if (!CircleUserLevelEnum.CREATOR.getLevel().equals(uc.getLevel())) {
            throw new ServiceException("不是圈主无法操作！");
        }
        boolean remove = circleService.removeById(circleId);
        if (!remove) {
            throw new ServiceException("数据不存在!", HttpStatus.DATA_NOT_FOUND_ERROR);
        }
    }

    @Override
    public List<UserCircle> listByUserId(Long userId) {
        LambdaQueryWrapper<UserCircle> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserCircle::getUserId, userId);
        return this.list(wrapper);
    }

    @Override
    public List<Circle> getUserCircle(Long userId) {
        return baseMapper.getUserCircle(userId);
    }

    @Override
    public boolean quit(Long userId, Long circleId) {
        Circle circle = circleService.getById(circleId);
        Long userCount = circle.getUserCount();
        userCount --;
        Circle updateCircle = new Circle();
        updateCircle.setId(circleId);
        updateCircle.setUserCount(userCount);
        circleService.updateById(updateCircle);

        LambdaQueryWrapper<UserCircle> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserCircle::getCircleId, circleId)
                .eq(UserCircle::getUserId, userId);
        return this.remove(wrapper);
    }

    @Override
    public boolean getIsCircleUser(Long userId, Long circleId) {
        LambdaQueryWrapper<UserCircle> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserCircle::getUserId, userId)
                .eq(UserCircle::getCircleId, circleId);
        UserCircle userCircle = this.getOne(wrapper);
        return userCircle != null;
    }

    @Override
    public void addExp(Long userId, Long circleId, Integer expNum) {
        LambdaQueryWrapper<UserCircle> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserCircle::getUserId, userId)
                .eq(UserCircle::getCircleId, circleId);
        UserCircle userCircle = this.getOne(wrapper);
        Integer exp = userCircle.getExp();
        exp += expNum;
        userCircle.setExp(exp);
        this.updateById(userCircle);
    }

    @Override
    public List<User> getUserListBySex(Long circleId, Integer sex) {
        return baseMapper.getUserListBySex(circleId, sex);
    }


    /**
     * 获取圈子管理人列表
     *
     * @param circleId
     * @return
     */
    @Override
    public List<User> getAdminUserByCircleId(Long circleId) {
        return baseMapper.getAdminUserByCircleId(circleId);
    }


    /**
     * 检查是否被禁止加入
     * 被踢出三次后，则永久禁止加入。
     *
     * @param circleId
     * @param userId
     * @return
     */
    private boolean checkForbiddenJoinCircle(Long circleId, Long userId) {
        LambdaQueryWrapper<CircleUserKick> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CircleUserKick::getCircleId, circleId)
                .eq(CircleUserKick::getUserId, userId);
        Long count = circleUserKickMapper.selectCount(wrapper);
        return count >= 3;
    }
}
